// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SPFarmHelper.cs" company="Collaboris Ltd.">
//   Copyright (c) Collaboris Ltd. All rights Reserved.
// </copyright>
// <summary>
//   Defines the SPFarmHelper type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Collaboris.SharePoint.Wss.Farm
{
    using System;

    using Collaboris.Utils;

    using Microsoft.SharePoint.Administration;

    /// <summary>
    /// Adds helper methods to the Sharepoint <see cref="SPFarm"/> class.
    /// </summary>
    public class SPFarmHelper : WssHelperBase
    {
        
        /// <summary>
        /// Adds a property to the farm property bag
        /// It first removes the old value if a value with the same name already exists. 
        /// </summary>
        /// <param name="farm"></param>
        /// <param name="name" ></param>
        /// <param name="propertyValue"></param>
        /// <typeparam name="T"></typeparam>
        public static void AddProperty<T>(SPFarm farm, string name, T propertyValue) // where T : ISerializable
        {
            try
            {
                TraceHelper.TraceMethodStart(TraceSwitch, "SPFarmHelper", "SPFarmHelper.SaveProperty");

                ValidationHelper.VerifyObjectArgument(farm, "farm");
                ValidationHelper.VerifyStringArgument(name, "name");
                ValidationHelper.VerifyObjectArgument(propertyValue, "propertyValue");
                ValidationHelper.VerifySerializableArgument(propertyValue, "propertyValue");

                string serialisedPropValue = SerialisationHelper.Serialize(propertyValue);

                if (farm.Properties.ContainsKey(name))
                {
                    //RemoveProperty(farm, name);
                    farm.Properties[name] = serialisedPropValue;
                }
                else
                {
                    farm.Properties.Add(name, serialisedPropValue);
                }

                farm.Update(true);
            }
            catch (Exception exception)
            {
                TraceHelper.TraceException(TraceSwitch, "SPFarmHelper", "SPFarmHelper.SaveProperty", exception);
                throw;
            }
            finally
            {
                TraceHelper.TraceMethodEnd(TraceSwitch, "SPFarmHelper", "SPFarmHelper.SaveProperty");
            }
        }

        /// <summary>
        /// Removes a property from the property bag
        /// It first removes the old value if a value with the same name already exists. 
        /// </summary>
        /// <param name="farm">The farm containing the property bag</param>
        /// <param name="name">The name of the property to be removed</param>
        public static void RemoveProperty(SPFarm farm, string name)
        {
            try
            {
                TraceHelper.TraceMethodStart(TraceSwitch, "SPFarmHelper", "SPFarmHelper.RemoveProperty");

                ValidationHelper.VerifyStringArgument(name, "name");
                ValidationHelper.VerifyObjectArgument(farm, "farm");

                if (farm.Properties.ContainsKey(name))
                {
                    // Remove does not work. It's another bug with SP
                    // farm.Properties.Remove(name);

                    // This is what we need to do to get around the bug
                    farm.Properties[name] = null;
                    farm.Update(true);
                }
            }
            catch (Exception exception)
            {
                TraceHelper.TraceException(TraceSwitch, "SPFarmHelper", "SPFarmHelper.RemoveProperty", exception);
                throw;
            }
            finally
            {
                TraceHelper.TraceMethodEnd(TraceSwitch, "SPFarmHelper", "SPFarmHelper.RemoveProperty");
            }
        }

        /// <summary>
        /// Gets a property value from the farm property bag
        /// </summary>
        /// <param name="farm"></param>
        /// <param name="propertyName"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetProperty<T>(SPFarm farm, string propertyName) // where T : ISerializable
        {
            try
            {
                TraceHelper.TraceMethodStart(TraceSwitch, "SPFarmHelper", "SPFarmHelper.GetProperty");

                ValidationHelper.VerifyObjectArgument(farm, "farm");
                ValidationHelper.VerifyStringArgument(propertyName, "propertyName");

                if (!farm.Properties.ContainsKey(propertyName))
                    return default(T);

                string serialisedPropValue = (string)farm.Properties[propertyName];
                if (serialisedPropValue != null)
                {
                    return SerialisationHelper.Deserialize<T>(serialisedPropValue);
                }

                return default(T);
            }
            catch (Exception exception)
            {
                TraceHelper.TraceException(TraceSwitch, "SPFarmHelper", "SPFarmHelper.GetProperty", exception);
                throw;
            }
            finally
            {
                TraceHelper.TraceMethodEnd(TraceSwitch, "SPFarmHelper", "SPFarmHelper.GetProperty");
            }
        }
    }
}